#include "config/ConfigManager.h"
#include "log/Logger.h"
#include <mutex>
#include <fstream>
#include <iostream>
#include "json/reader.h"

std::mutex g_ConfigManagerMtx;

CConfigManager* CConfigManager::m_pInstance = nullptr;

CConfigManager::CConfigManager()
    :m_strConfigPath("")
{
    m_jsnConfig.clear();
}

CConfigManager::~CConfigManager()
{
    m_strConfigPath.clear();
    m_jsnConfig.clear();
}

CConfigManager* CConfigManager::instance()
{
   if(nullptr == m_pInstance)
   {
       g_ConfigManagerMtx.lock();
       if(nullptr == m_pInstance)
       {
           m_pInstance = new CConfigManager();
       }
       g_ConfigManagerMtx.unlock();
       return m_pInstance;
   }
   else 
   {
       return m_pInstance;
   }

}

bool CConfigManager::loadConfig(const std::string & strConfigFilePath, Json::Value & jsnConfig)
{
    std::ifstream ifs(strConfigFilePath, std::ifstream::binary);
    // get pointer to associated buffer object
    std::filebuf* pbuf = ifs.rdbuf();
    // get file size using buffer's members
    std::size_t size = pbuf->pubseekoff(0, ifs.end, ifs.in);
    pbuf->pubseekpos(0, ifs.in);
    // allocate memory to contain file data
    char* pBuffer = new char[size];
    if (nullptr == pBuffer)
    {
        // log
        LOG_ERROR("nullptr == pBuffer");
        return false;
    }
    // get file data
    pbuf->sgetn(pBuffer, size);
    ifs.close();
    // write content to stdout
    std::string strBuf = pBuffer;
    delete[] pBuffer;

    if (!strBuf.empty())
    {
        Json::Reader tmpReader;
        //Json::CharReader
        Json::Value tmpValue;
        if (!tmpReader.parse(strBuf, tmpValue))
        {
            LOG_ERROR("logfile :" << strConfigFilePath << " parse error");
            return false;
        }
        jsnConfig = tmpValue;
        m_jsnConfig = tmpValue;
        m_strConfigPath = strConfigFilePath;
    }
    return true;
}

bool CConfigManager::getConfig(const std::string & strConfigName, Json::Value & jsnConfig)
{
    if (strConfigName.empty())
    {
        LOG_ERROR("strConfigName.empty()");
        return false;
    }
    LOG_DEBUG("getConfig cfgname : "<<strConfigName);
    if ("all" == strConfigName)
    {
        jsnConfig = m_jsnConfig;
    }
    if ( m_jsnConfig.isMember(strConfigName))
    {
        jsnConfig = m_jsnConfig[strConfigName];
    }
    return true;
}

bool CConfigManager::setConfig(const std::string & strConfigName, Json::Value & jsnConfig)
{
    if (strConfigName.empty())
    {
        LOG_ERROR("strConfigName.empty()");
        return false;
    }
    if (!jsnConfig.isNull() && m_jsnConfig.isMember(strConfigName))
    {
        m_jsnConfig[strConfigName] = jsnConfig;
        Json::StyledWriter writer;
        std::ofstream fout(m_strConfigPath);
        if (!fout)
        {
            LOG_ERROR("open file error !");;
        }
        else
        {
            fout.clear();
            fout <<m_jsnConfig.toStyledString() << std::endl;
            fout.close();
        }
    }
    return true;
}

